import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;

/**
 * \* Created with IntelliJ IDEA.
 * \* User: 冯若航
 * \* Date: 2021/5/12
 * \* Time: 17:05
 * \* To change this template use File | Settings | File Templates.
 * \* Description:输入一个字符串，打印出该字符串中字符的所有排列
 * \
 */
public class 字符串的排列 {
    //为了让递归函数添加结果方便，定义到函数之外，这样无需带到递归函数的参数列表中
    List<String> res=new ArrayList<>();
    char[]c;
    public String[] permutation(String s) {
        c=s.toCharArray();
        dfs(0);
        //将字符串数组ArrayList转化为String类型数组
        return res.toArray(new String[res.size()]);
    }

    void swap(int i,int x){
        char temp=c[i];
        c[i]=c[x];
        c[x]=temp;
    }

    void dfs(int x){
        //当递归函数到达第三层，就返回，因为此时第二第三个位置已经发生了交换
        if(x==c.length-1){
            //将字符数组转换为字符串
            //res.add(c.toString());  这种会返回乱码
            res.add(String.valueOf(c));
            return;
        }

        //为了防止同一层递归出现重复元素
        HashSet<Character> set=new HashSet<>();
        for(int i=x;i<c.length;i++){
            //发生剪枝，当包含这个元素的时候，直接跳过
            if(set.contains(c[i])){
                continue;
            }

            set.add(c[i]);
            //交换元素，这里很是巧妙，当在第二层dfs(1),x = 1,那么i = 1或者 2， 不是交换1和1，要就是交换1和2
            swap(i,x);
            //进入下一层递归
            dfs(x + 1);
            //返回时交换回来，这样保证到达第1层的时候，一直都是abc。这里捋顺一下，开始一直都是abc，那么第一位置总共就3个交换
            //分别是a与a交换，这个就相当于 x = 0, i = 0;
            //     a与b交换            x = 0, i = 1;
            //     a与c交换            x = 0, i = 2;
            //就相当于上图中开始的三条路径
            //第一个元素固定后，每个引出两条路径,
            //     b与b交换            x = 1, i = 1;
            //     b与c交换            x = 1, i = 2;
            //所以，结合上图，在每条路径上标注上i的值，就会非常容易好理解了
            swap(i,x);
        }
    }

}